%{
 /* Aqui, pode-se inserir qualquer codigo C necessario ah compilacao
	* final do parser. Sera copiado tal como esta no inicio do y.tab.c
	* gerado por Yacc.
	*/
	#include <stdio.h>
	#include <stdlib.h>
	#include "lista.h"
	#include "node.h"
	#include "symbol_table.h"
	#include <string.h>
	#define UNDEFINED_SYMBOL_ERROR -21
	#define TYPE_MISMATCH_ERROR -20
	#define TYPE_INT 1
	#define TYPE_CHAR 2
	#define TYPE_REAL 3
	#define TYPE_DOUBLE 4

	#define SIZE_INT 4
	#define SIZE_CHAR 1
	#define SIZE_REAL 4
	#define SIZE_DOUBLE 8


 Node* syntax_tree;
 node_tac *codigo_tac;
 int desloc = 0;
 int temp = 0;
 
typedef struct uniqueType_att_t {
    int tipo;
    int size;
} uniqueType_att_t;

typedef struct doubleList_att_t {
    int *inicio;
    int tam_arrays;
    int *size;
    int size_total;
} doubleList_att_t;

typedef struct typeListAtt_t {
    int tipo;
    int size;
    int w;
    doubleList_att_t *listadupla;
} typeListAtt_t;

typedef struct exprAtt {
    char *var;
    node_tac *code;
    int tipo;
} exprAtt;

typedef struct listExprAtt {
    exprAtt **expr;
    int tam;
} listExprAtt;

typedef struct attArray {
    int c;
    int nd;
    int *size;
    int w;
} attArray;

typedef struct attOpera {
    char *oper_int;
    char *oper_flut;
} attOpera;

symbol_t symbol_table;
void setSonsTable(Node *tipo, Node *decl);
void notDeclared(char *var);
void typeError();
int addCodeToList(node_tac **code, listExprAtt *lista);

%}
%union{
 char* cadeia;
 Node* no;
};
%token< cadeia > IDF
%token< cadeia > INT
%token< cadeia > DOUBLE
%token< cadeia > REAL
%token< cadeia > CHAR
%token< cadeia > QUOTE
%token< cadeia > DQUOTE
%token< cadeia > LE
%token< cadeia > GE
%token< cadeia > EQ
%token< cadeia > NE
%token< cadeia > AND
%token< cadeia > OR
%token< cadeia > NOT
%token< cadeia > IF
%token< cadeia > THEN
%token< cadeia > ELSE
%token< cadeia > WHILE
%token< cadeia > INT_LIT
%token< cadeia > F_LIT
%token< cadeia > END
%token< cadeia > TRUE
%token< cadeia > FALSE
%token< cadeia > PRINTF
%token< cadeia > ';'
%token< cadeia > ':'
%token< cadeia > ','
%token< cadeia > '['
%token< cadeia > ']'
%token< cadeia > '('
%token< cadeia > ')'
%token< cadeia > '{'
%token< cadeia > '}'
%token< cadeia > '=' 
%token< cadeia > '*' 
%token< cadeia > '/' 
%token< cadeia > '+' 
%token< cadeia > '-' 
%token< cadeia > '>' 
%token< cadeia > '<' 
%type< no > code
%type< no > declaracoes
%type< no > declaracao
%type< no > listadeclaracao
%type< no > tipo
%type< no > tipounico
%type< no > tipolista
%type< no > listadupla
%type< no > acoes
%type< no > comando
%type< no > lvalue
%type< no > listaexpr
%type< no > expr
%type< no > chamaproc
%type< no > enunciado
%type< no > fiminstcontrole
%type< no > expbool
%type< no > opera

%left '+' '-'
%left '*' '/'
%left OR
%left AND
%left NOT

%start code
 /* A completar com seus tokens - compilar com 'yacc -d' */
%%
code: declaracoes acoes {
		Node** aux;
		node_tac *at = NULL;
		node_tac *code = ((node_tac *)$2->attribute);
		pack_nodes(&aux, 0, $1);
		pack_nodes(&aux, 1, $2);
		
		cat_tac(&at, &code);
		syntax_tree = create_node(@1.first_line, program_node, NULL, at, 2, aux);
		$$=syntax_tree;
	}
	
	| acoes {
		syntax_tree = $1;
		$$ = syntax_tree;
	};
	
declaracoes: declaracao ';'{
				Node **aux;
				pack_nodes(&aux, 0, $1);
				pack_nodes(&aux, 1, create_leaf(@1.first_line, semicolon_node, ";", NULL));
				$$=create_node(@1.first_line, decl_node, NULL, NULL, 2, aux);
				}
			| declaracoes declaracao ';'{
				Node **aux;
				pack_nodes(&aux, 0, $1);
				pack_nodes(&aux, 1, $2);
				pack_nodes(&aux, 2, create_leaf(@1.first_line, semicolon_node, ";", NULL));
				$$=create_node(@1.first_line, decl_node, NULL, NULL, 3, aux);
			};
				
declaracao: tipo ':' listadeclaracao {
				
				Node **aux;
				Node *p;
				pack_nodes(&aux, 0, $1);
				pack_nodes(&aux, 1, $3);
				setSonsTable((Node *)$1, (Node *)$3);
				
				$$=create_node(@1.first_line, decl_node, NULL, NULL, 2, aux);
				};
				
listadeclaracao: IDF {
					$$=create_leaf(@1.first_line, idf_node, $1, NULL);
				} 
				
				| IDF ',' listadeclaracao {
					Node** aux;
					pack_nodes(&aux, 0, create_leaf(@1.first_line, idf_node, $1, NULL));
					pack_nodes(&aux, 1, $3);
					$$ = create_node(@1.first_line, decl_list_node, NULL, NULL, 2, aux);
				};
				
tipo: tipounico {
			$$=$1;
		}
		| tipolista {
			$$=$1;
		};
		
tipounico: INT {
				uniqueType_att_t *at = malloc(sizeof(uniqueType_att_t));
				at->tipo = TYPE_INT;
				at->size = SIZE_INT;
				$$ = create_leaf(@1.first_line, int_node, "int", at);
			}
			| DOUBLE {
				uniqueType_att_t *at = malloc(sizeof(uniqueType_att_t));
				at->tipo = TYPE_DOUBLE;
				at->size = SIZE_DOUBLE;
				$$ = create_leaf(@1.first_line, double_node, "double", at);
			}
			| REAL {
				uniqueType_att_t *at = malloc(sizeof(uniqueType_att_t));
				at->tipo = TYPE_REAL;
				at->size = SIZE_REAL;
				$$ = create_leaf(@1.first_line, real_node, "real", at);
			}
			| CHAR {
				uniqueType_att_t *at = malloc(sizeof(uniqueType_att_t));
				at->tipo = TYPE_CHAR;
				at->size = SIZE_CHAR;
				$$ = create_leaf(@1.first_line, char_node, "char", at);
			};
tipolista: INT '(' listadupla ')' {
				Node **aux;
				typeListAtt_t *at = malloc(sizeof(typeListAtt_t));
				doubleList_att_t *a = ((doubleList_att_t *) $3->attribute);
				pack_nodes(&aux, 0, create_leaf(@1.first_line, int_node, "int", NULL));
				pack_nodes(&aux, 1, create_leaf(@1.first_line, abre_colc_node, "(", NULL));
				pack_nodes(&aux, 2, $3);
				pack_nodes(&aux, 3, create_leaf(@1.first_line, fecha_colc_node, ")", NULL));
				at->tipo = TYPE_INT;
				at->size = a->size_total*SIZE_INT;
				at->listadupla = a;
				at->w = SIZE_INT;
				$$ = create_node(@1.first_line, tipolista_node, NULL, at, 4, aux);
			}
			| DOUBLE '(' listadupla ')' {
				Node **aux;
				typeListAtt_t *at=malloc(sizeof(typeListAtt_t));
				doubleList_att_t *a=((doubleList_att_t *) $3->attribute);
				pack_nodes(&aux, 0, create_leaf(@1.first_line, double_node, "double", NULL));
				pack_nodes(&aux, 1, create_leaf(@1.first_line, abre_colc_node, "(", NULL));
				pack_nodes(&aux, 2, $3);
				pack_nodes(&aux, 3, create_leaf(@1.first_line, fecha_colc_node, ")", NULL));
				at->tipo=TYPE_DOUBLE;
				at->size=a->size_total*SIZE_DOUBLE;
				at->w=SIZE_DOUBLE;
				at->listadupla=a;
				$$=create_node(@1.first_line, tipolista_node, NULL, at, 4, aux);
			}
			| REAL '(' listadupla ')' {
				Node **aux;
				typeListAtt_t *at = malloc(sizeof(typeListAtt_t));
				doubleList_att_t *a = ((doubleList_att_t *) $3->attribute);
				pack_nodes(&aux, 0, create_leaf(@1.first_line, real_node, "real", NULL));
				pack_nodes(&aux, 1, create_leaf(@1.first_line, abre_colc_node, "(", NULL));
				pack_nodes(&aux, 2, $3);
				pack_nodes(&aux, 3, create_leaf(@1.first_line, fecha_colc_node, ")", NULL));
				at->tipo=TYPE_REAL;
				at->size=a->size_total*SIZE_REAL;
				at->listadupla = a;
				at->w = SIZE_REAL;
				$$=create_node(@1.first_line, tipolista_node, NULL, at, 4, aux);
			}
			| CHAR '(' listadupla ')'{
				Node **aux;
				typeListAtt_t *at=malloc(sizeof(	typeListAtt_t));
				doubleList_att_t *a=((doubleList_att_t *) $3->attribute);
				pack_nodes(&aux, 0, create_leaf(@1.first_line, char_node, "char", NULL));
				pack_nodes(&aux, 1, create_leaf(@1.first_line, abre_colc_node, "(", NULL));
				pack_nodes(&aux, 2, $3);
				pack_nodes(&aux, 3, create_leaf(@1.first_line, fecha_colc_node, ")", NULL));
				at->tipo=TYPE_CHAR;
				at->size=a->size_total*SIZE_CHAR;
				at->listadupla=a;
				at->w=SIZE_CHAR;
				$$=create_node(@1.first_line, tipolista_node, NULL, at, 4, aux);
			};
			
listadupla: INT_LIT ':' INT_LIT{
				Node **aux;
				doubleList_att_t *at=malloc(sizeof(doubleList_att_t));
						
				pack_nodes(&aux, 0, create_leaf(@1.first_line, intlit_node, $1, NULL));
				pack_nodes(&aux, 1, create_leaf(@1.first_line, doispontos_node, ":", NULL));
				pack_nodes(&aux, 2, create_leaf(@1.first_line, intlit_node, $3, NULL));
				at->inicio=malloc(sizeof(int));
				at->inicio[0]=atoi($1);
				at->tam_arrays=1;
				at->size=malloc(sizeof(int));
				at->size[0]= atoi($3) - at->inicio[0] + 1;
				at->size_total=at->size[0];
				
				$$=create_node(@1.first_line, listadupla_node, NULL, at, 3, aux);
			}
			| INT_LIT ':' INT_LIT ',' listadupla{
				Node **aux;
				doubleList_att_t *at =
					malloc(sizeof(doubleList_att_t));
				doubleList_att_t *a;
				int i;
				pack_nodes(&aux, 0, create_leaf(@1.first_line, intlit_node, $1, NULL));
				pack_nodes(&aux, 1, create_leaf(@1.first_line, doispontos_node, ":", NULL));
				pack_nodes(&aux, 2, create_leaf(@1.first_line, intlit_node, $3, NULL));
				pack_nodes(&aux, 3, create_leaf(@1.first_line, comma_node, ", ", NULL));
				pack_nodes(&aux, 4, $5);
				
				a = ((doubleList_att_t *) $5->attribute);
				
				at->tam_arrays = a->tam_arrays + 1;
				at->inicio = malloc(sizeof(int) *at->tam_arrays);
				at->inicio[0] = atoi($1);
				
				for(i=0;i< at->tam_arrays -1; i++)
					at->inicio[i+1] = a->inicio[i];
					
				at->size = malloc(sizeof(int) *at->tam_arrays);
				at->size[0] = atoi($3) - at->inicio[0] + 1;
				
				for(i=0; i < at->tam_arrays -1; i++)
					at->size[i+1] = a->size[i];
					
				at->size_total=at->size[0] *a->size_total;
				$$=create_node(@1.first_line, listadupla_node, NULL, at, 5, aux);
			};
acoes: comando ';' {
		Node** aux;
		node_tac *at=NULL;
		node_tac *code=((node_tac *)$1->attribute);
		pack_nodes(&aux, 0, $1);
		pack_nodes(&aux, 1, create_leaf(@1.first_line, semicolon_node, ";", NULL));
		cat_tac(&at, &code);
		$$=create_node(@1.first_line, acoes_node, NULL, at, 2, aux);
	}
	| comando ';' acoes{
		Node** aux;
		node_tac *at=NULL;
		node_tac *code=((node_tac *)$1->attribute);
		pack_nodes(&aux, 0, $1);
		pack_nodes(&aux, 1, create_leaf(@1.first_line, semicolon_node, ";", NULL));
		pack_nodes(&aux, 2, $3);
		
		cat_tac(&at, &code);
		code=((node_tac *)$3->attribute);
		cat_tac(&at, &code);
		$$=create_node(@1.first_line, acoes_node, NULL, at, 3, aux);
	};
comando: lvalue '=' expr {
			Node** aux;
			node_tac *at=NULL;
			exprAtt *l=((exprAtt *)$1->attribute);
			exprAtt *r=((exprAtt *)$3->attribute);
			pack_nodes(&aux, 0, $1);
			pack_nodes(&aux, 1, create_leaf(@1.first_line, attrib_node, "=", NULL));
			pack_nodes(&aux, 2, $3);
			cat_tac(&at, &(l->code));
			cat_tac(&at, &(r->code));
			if(((r->tipo == TYPE_CHAR) && 
			(l->tipo != TYPE_CHAR))			||
			((r->tipo != TYPE_CHAR) &&
			(l->tipo == TYPE_CHAR))			||
			((r->tipo == TYPE_DOUBLE) && 
			(l->tipo != TYPE_DOUBLE))		||
			((r->tipo == TYPE_REAL) &&
			(l->tipo == TYPE_INT)))
			{
			typeError();
			return TYPE_MISMATCH_ERROR;
			}
			append_inst_tac(&at, create_inst_tac(3, l->var, r->var, ":=", ""));
			$$=create_node(@1.first_line, comando_node, NULL, at, 3, aux);
		}
		| enunciado {
			$$=$1;
		};
		
lvalue: IDF {
			exprAtt *at = malloc(sizeof(exprAtt));
			entry_t *ref;
			if((ref = lookup(symbol_table, $1)) == NULL)
			{
				notDeclared($1);
				return UNDEFINED_SYMBOL_ERROR;
			}
			
			at->var = malloc(sizeof(char)*8);

			sprintf(at->var, "%03d%s", ref->desloc, "(SP)");

			at->code = NULL;
			at->tipo = ref->type;
			
			$$ = create_leaf(@1.first_line, idf_node, $1, at);
		}
				
		| IDF '[' listaexpr ']'{
			Node **aux;	
			pack_nodes(&aux, 0, create_leaf(@1.first_line, idf_node, $1, NULL));
			pack_nodes(&aux, 1, create_leaf(@1.first_line, abre_colc_node, "[", NULL));
			pack_nodes(&aux, 2, $3);
			pack_nodes(&aux, 3, create_leaf(@1.first_line, fecha_colc_node, "]", NULL));
		
			$$ = create_node(@1.first_line, lvalue_node, NULL, NULL, 4, aux);
		};
		
listaexpr: expr {

		Node **aux;
		listExprAtt *at =malloc(sizeof(listExprAtt));
		pack_nodes(&aux, 0, $1);
		at->tam=1;
		at->expr= malloc(sizeof(exprAtt *));
		at->expr[0]=((exprAtt *)$1->attribute);
		$$ = create_node(@1.first_line, listaexpr_node, NULL, at, 1, aux);
	}
	| expr ',' listaexpr {
		Node** aux;
		listExprAtt *at =malloc(sizeof(listExprAtt));
		listExprAtt *a=((listExprAtt *) $3->attribute);
		
		pack_nodes(&aux, 0, $1);
		pack_nodes(&aux, 1, $3);
		at->tam=a->tam + 1;
		at->expr=malloc(sizeof(exprAtt *) *a->tam);
		at->expr[0]=((exprAtt *)$1->attribute);
		
		int i;
		for(i = 0; i < a->tam; i++)
			at->expr[i+1] = a->expr[i];
			
		$$ = create_node(@1.first_line, listaexpr_node, NULL, at, 2, aux);
	};

opera: '+' {
			attOpera *at = malloc(sizeof(attOpera));
			at->oper_int = malloc(sizeof(char) * 4);
			at->oper_flut = malloc(sizeof(char) * 5);
			
			strcpy(at->oper_int, "ADD");
			strcpy(at->oper_flut, "FADD");
			$$ = create_leaf(@1.first_line, plus_node, "+", at);
		}
		| '-' {
			attOpera *at = malloc(sizeof(attOpera));
			at->oper_int= malloc(sizeof(char) * 4);
			at->oper_flut= malloc(sizeof(char) * 5);
			
			strcpy(at->oper_int, "SUB");
			strcpy(at->oper_flut, "FSUB");
			$$ = create_leaf(@1.first_line, minus_node, "-", at);
		}
		| '*' {
			attOpera *at = malloc(sizeof(attOpera));
			at->oper_int = malloc(sizeof(char)*4);
			at->oper_flut = malloc(sizeof(char)*5);
			strcpy(at->oper_int, "MUL");
			strcpy(at->oper_flut, "FMUL");
			$$=create_leaf(@1.first_line, mult_node, "*", at);
		}
		
		| '/' {
			attOpera *at = malloc(sizeof(attOpera));
			at->oper_int = malloc(sizeof(char) * 4);
			at->oper_flut = malloc(sizeof(char) * 5);
			
			strcpy(at->oper_int, "DIV");
			strcpy(at->oper_flut, "FDIV");
			$$ = create_leaf(@1.first_line, div_node, "/", at);
		};
		
expr: expr opera expr {

		Node** aux;
		exprAtt *at = malloc(sizeof(exprAtt));
		exprAtt *l = ((exprAtt *) $1->attribute);
		exprAtt *r = ((exprAtt *) $3->attribute);
		attOpera *o = ((attOpera *) $2->attribute);

		pack_nodes(&aux, 0, $1);
		pack_nodes(&aux, 1, $2);
		pack_nodes(&aux, 2, $3);

		at->code = NULL;
		cat_tac(&(at->code), &(l->code));
		cat_tac(&(at->code), &(r->code));
		
		at->var = malloc(sizeof(char) * 8);
		
		if( ( l->tipo == TYPE_CHAR ) || ( r->tipo == TYPE_CHAR ) )
		{
			typeError();
			return TYPE_MISMATCH_ERROR;
		}
		else if((l->tipo == TYPE_INT) && (r->tipo == TYPE_INT))
		{
			sprintf(at->var, "%03d%s", temp, "(Rx)");
			temp += SIZE_INT;
			
			append_inst_tac(&(at->code), create_inst_tac(3, at->var, l->var, o->oper_int, r->var));
			at->tipo=TYPE_INT;
		}
		else if((l->tipo == TYPE_DOUBLE) || (r->tipo == TYPE_DOUBLE))
		{
			char *le=malloc(sizeof(char)*8);
			char *ri=malloc(sizeof(char)*8);
			if(l->tipo != TYPE_DOUBLE)
			{
				sprintf(le, "%03d%s", temp, "(Rx)");
				temp += SIZE_DOUBLE;
				append_inst_tac(&(at->code), create_inst_tac(3, le, l->var, ":=", ""));
			}
			else
				strcpy(le, l->var);
		
			if(r->tipo != TYPE_DOUBLE)
			{
				sprintf(ri, "%03d%s", temp, "(Rx)");
				temp += SIZE_DOUBLE;
								
				append_inst_tac(&(at->code), create_inst_tac(3, ri, r->var, ":=", ""));
			}
			else
				strcpy(ri, r->var);
		
			sprintf(at->var, "%03d%s", temp, "(Rx)");
			temp += SIZE_DOUBLE;
			
			append_inst_tac(&(at->code), create_inst_tac(3, at->var, le, o->oper_flut, ri));
			at->tipo=TYPE_DOUBLE;
		}
		else if((l->tipo == TYPE_REAL) || (r->tipo == TYPE_REAL))
		{
			char *le = malloc(sizeof(char)*8);
			char *ri = malloc(sizeof(char)*8);
			if(l->tipo != TYPE_REAL)
			{
				sprintf(le, "%03d%s", temp, "(Rx)");
				temp += SIZE_REAL;
				append_inst_tac(&(at->code), create_inst_tac(3, le, l->var, ":=", ""));
			}
			else
				strcpy(le, l->var);
	
			if(r->tipo != TYPE_REAL)
			{
				sprintf(ri, "%03d%s", temp, "(Rx)");
				temp += SIZE_REAL;
				append_inst_tac(&(at->code), create_inst_tac(3, ri, r->var, ":=", ""));
			}
			else
				strcpy(ri, r->var);
				
			sprintf(at->var, "%03d%s", temp, "(Rx)");
			temp += SIZE_REAL;
			append_inst_tac(&(at->code), create_inst_tac(3, at->var, le, o->oper_flut, ri));
			at->tipo=TYPE_REAL;
		}
		
		$$=create_node(@1.first_line, expr_node, NULL, at, 3, aux);
	}
	| '(' expr ')'{
		//Node** aux;
		//pack_nodes(&aux, 0, create_leaf(@1.first_line, abre_parent_node, "(", NULL));
		//pack_nodes(&aux, 1, $2);
		//pack_nodes(&aux, 2, create_leaf(@1.first_line, fecha_parent_node, ")", NULL));
		//$$ = create_node(@1.first_line, expr_node, NULL, NULL, 3, aux);
		$$=$2;
	}
	| INT_LIT {
		exprAtt *at = malloc(sizeof(exprAtt));
		at->var = malloc(sizeof(char)*(strlen($1)+1));
		strcpy(at->var, $1);
		at->tipo = TYPE_INT;
		at->code = NULL;
		
		$$=create_leaf(@1.first_line, intlit_node, $1, at);
	}
	| F_LIT {
		exprAtt *at=malloc(sizeof(exprAtt));
		at->var=malloc(sizeof(char)*(strlen($1)+1));
		strcpy(at->var, $1);
		at->tipo=TYPE_REAL;
		at->code=NULL;
		$$=create_leaf(@1.first_line, flit_node, $1, at);
	}
	| lvalue {
		$$=$1;
	}
	| chamaproc {
		$$=$1;
	};
	
chamaproc: IDF '(' listaexpr ')'{
						Node** aux;
						pack_nodes(&aux, 0, create_leaf(@1.first_line, idf_node, $1, NULL));
						pack_nodes(&aux, 1, create_leaf(@1.first_line, abre_parent_node, "(", NULL));
						pack_nodes(&aux, 2, $3);
						pack_nodes(&aux, 3, create_leaf(@1.first_line, fecha_parent_node, ")", NULL));
						$$=create_node(@1.first_line, chama_proc_node, NULL, NULL, 4, aux);
				}
			;
enunciado: expr {
				node_tac *at=NULL;
				node_tac *code=((exprAtt *)$1->attribute)->code;
				Node **aux;
				cat_tac(&at, &code);
				
				pack_nodes(&aux, 0, $1);
				$$=create_node(@1.first_line, enunciado_node, NULL, at, 1, aux);
			}
			| IF '(' expbool ')' THEN acoes fiminstcontrole{
				Node** aux;
				pack_nodes(&aux, 0, create_leaf(@1.first_line, if_node, "if", NULL));
				pack_nodes(&aux, 1, create_leaf(@1.first_line, abre_parent_node, "(", NULL));
				pack_nodes(&aux, 2, $3);
				pack_nodes(&aux, 3, create_leaf(@1.first_line, fecha_parent_node, ")", NULL));
				pack_nodes(&aux, 4, create_leaf(@1.first_line, then_node, "then", NULL));
				pack_nodes(&aux, 5, $6);
				pack_nodes(&aux, 6, $7);
				$$=create_node(@1.first_line, enunciado_node, NULL, NULL, 7, aux);
			}
			
			| WHILE '(' expbool ')' '{' acoes '}'{
				Node** aux;
				pack_nodes(&aux, 0, create_leaf(@1.first_line, while_node, "while", NULL));
				pack_nodes(&aux, 1, create_leaf(@1.first_line, abre_parent_node, "(", NULL));
				pack_nodes(&aux, 2, $3);
				pack_nodes(&aux, 3, create_leaf(@1.first_line, fecha_parent_node, ")", NULL));
				pack_nodes(&aux, 4, create_leaf(@1.first_line, abre_chave_node, "{", NULL));
				pack_nodes(&aux, 5, $6);
				pack_nodes(&aux, 6, create_leaf(@1.first_line, fecha_chave_node, "}", NULL));
				$$ = create_node(@1.first_line, enunciado_node, NULL, NULL, 7, aux);
			}
			
			| PRINTF '(' expr ')'{
					exprAtt *arg=((exprAtt *)$3->attribute);
					node_tac *at=NULL;
					Node** aux;
					cat_tac(&at, &(arg->code));
					if(arg->tipo == TYPE_CHAR)
					{
						typeError();
						return TYPE_MISMATCH_ERROR;
					}
					else if(arg->tipo == TYPE_INT)
						append_inst_tac(&at, create_inst_tac(1, arg->var, "", "", ""));
					else
						append_inst_tac(&at, create_inst_tac(2, arg->var, "", "", ""));
	
					pack_nodes(&aux, 0, create_leaf(@1.first_line, print_node, "print", NULL));
					pack_nodes(&aux, 1, create_leaf(@1.first_line, abre_parent_node, "(", NULL));
					pack_nodes(&aux, 2, $3);
					pack_nodes(&aux, 3, create_leaf(@1.first_line, fecha_parent_node, ")", NULL));
					$$=create_node(@1.first_line, enunciado_node, NULL, at, 7, aux);
				};

fiminstcontrole: END {
					$$=create_leaf(@1.first_line, end_node, "end", NULL);
				}
				| ELSE acoes END {
					Node** aux;
					pack_nodes(&aux, 0, create_leaf(@1.first_line, else_node, "else", NULL));
					pack_nodes(&aux, 1, $2);
					pack_nodes(&aux, 2, create_leaf(@1.first_line, end_node, "end", NULL));
					$$=create_node(@1.first_line, fimcontrole_node, NULL, NULL, 3, aux);
				};
expbool: TRUE {
			$$=create_leaf(@1.first_line, true_node, "true", NULL);
		}
		| FALSE {
			$$=create_leaf(@1.first_line, false_node, "false", NULL);
		}
		| '(' expbool ')'{
			Node** aux;
			pack_nodes(&aux, 0, create_leaf(@1.first_line, abre_parent_node, "(", NULL));
			pack_nodes(&aux, 1, $2);
			pack_nodes(&aux, 2, create_leaf(@1.first_line, fecha_parent_node, ")", NULL));
			$$=create_node(@1.first_line, expbool_node, NULL, NULL, 3, aux);
		}
		| expbool AND expbool {
			Node** aux;
			pack_nodes(&aux, 0, $1);
			pack_nodes(&aux, 1, create_leaf(@1.first_line, and_node, "&&", NULL));
			pack_nodes(&aux, 2, $3);
			$$=create_node(@1.first_line, expbool_node, NULL, NULL, 3, aux);
		}
		| expbool OR expbool {
			Node** aux;
			pack_nodes(&aux, 0, $1);
			pack_nodes(&aux, 1, create_leaf(@1.first_line, or_node, "||", NULL));
			pack_nodes(&aux, 2, $3);
			$$=create_node(@1.first_line, expbool_node, NULL, NULL, 3, aux);
		}
		| NOT expbool {
			Node ** aux;
			pack_nodes(&aux, 0, create_leaf(@1.first_line, not_node, "!", NULL));
			pack_nodes(&aux, 1, $2);
			$$=create_node(@1.first_line, expbool_node, NULL, NULL, 2, aux);
		}
		| expr '>' expr {
			Node** aux;
			pack_nodes(&aux, 0, $1);
			pack_nodes(&aux, 1, create_leaf(@1.first_line, sup_node, ">", NULL));
			pack_nodes(&aux, 2, $3);
			$$=create_node(@1.first_line, expbool_node, NULL, NULL, 3, aux);
		}
		| expr '<' expr {
			Node** aux;
			pack_nodes(&aux, 0, $1);
			pack_nodes(&aux, 1, create_leaf(@1.first_line, inf_node, "<", NULL));
			pack_nodes(&aux, 2, $3);
			$$=create_node(@1.first_line, expbool_node, NULL, NULL, 3, aux);
		}
		| expr LE expr {
			Node** aux;
			pack_nodes(&aux, 0, $1);
			pack_nodes(&aux, 1, create_leaf(@1.first_line, inf_eq_node, "<=", NULL));
			pack_nodes(&aux, 2, $3);
			$$=create_node(@1.first_line, expbool_node, NULL, NULL, 3, aux);
		}
		| expr GE expr {
				Node** aux;
				pack_nodes(&aux, 0, $1);
				pack_nodes(&aux, 1, create_leaf(@1.first_line, sup_eq_node, ">=", NULL));
				pack_nodes(&aux, 2, $3);
				$$=create_node(@1.first_line, expbool_node, NULL, NULL, 3, aux);
		}
		| expr EQ expr {
			Node** aux;
			pack_nodes(&aux, 0, $1);
			pack_nodes(&aux, 1, create_leaf(@1.first_line, eq_node, "==", NULL));
			pack_nodes(&aux, 2, $3);
			$$=create_node(@1.first_line, expbool_node, NULL, NULL, 3, aux);
		}
		| expr NE expr {
			Node** aux;
			pack_nodes(&aux, 0, $1);
			pack_nodes(&aux, 1, create_leaf(@1.first_line, neq_node, "!=", NULL));
			pack_nodes(&aux, 2, $3);
			$$=create_node(@1.first_line, expbool_node, NULL, NULL, 3, aux);
		};
%%
 /* A partir daqui, insere-se qlqer codigo C necessario.
 */
char* progname;
extern FILE* yyin;



void notDeclared(char *var)
{
	printf("UNDEFINED SYMBOL. A variavel %s nao foi declarada.\n", var);
}
void typeError()
{
	printf("ERRO DE COMPATIBILIDADE DE TIPO. Quem te ensinou a programar?\n");
}
int addCodeToList(node_tac **code, listExprAtt *lista)
{
	int i;
	for(i=0; i< lista->tam;i++)
	{
		if(lista->expr[i]->tipo != TYPE_INT)
		{
			typeError();
			return 0;
		}
		cat_tac(code, &(lista->expr[i]->code));
	}
	return 1;
}
void setSonsTable(Node *tipo, Node *decl)
{
	if(decl->type == idf_node)
	{
		entry_t *entrada = malloc(sizeof(entry_t));
		entrada->name=malloc(sizeof(char) * (strlen(decl->lexeme) + 1));
		strcpy(entrada->name, decl->lexeme);
		
		if((tipo->type == int_node) || 
			(tipo->type == real_node) ||
			(tipo->type == double_node) ||
			(tipo->type == char_node))
			{
				entrada->type = ((uniqueType_att_t *)tipo->attribute)->tipo;
				entrada->size = ((uniqueType_att_t *)tipo->attribute)->size;
				entrada->extra = NULL;
			}
		
		
			
		entrada->desloc = desloc;
		desloc += entrada->size;
		insert(&symbol_table, entrada);
	}
	else
	{
		int index;
		for(index = 0; index < nb_of_children(decl); index++)
		{
			setSonsTable(tipo, child(decl, index));
		}
	}
}
void usage(char *nome)
{
	printf("uso: %s [-o <output_file>] <input_file>. Try again!\n", nome);
	exit(-1);
}
int main(int argc, char* argv[]) 
{
	int outfile = 0;
	FILE *saida;
	char *nome;
	
	temp = 0;
	
	init_table(&symbol_table);
	
	if((argc == 1) || (argc == 3) || (argc > 4)) {
		usage(argv[0]);
	}
	
	if(argc == 4)
	{
		if(strcmp(argv[1], "-o") != 0)
		{
			if(strcmp(argv[2], "-o") != 0)
			usage(argv[0]);
			nome=(char *)malloc(sizeof(char)*(strlen(argv[3]) + 5));
			nome[0]='\0';
			strcat(nome, argv[3]);
		}
		else {
			nome=(char *)malloc(sizeof(char)*(strlen(argv[2]) + 5));
			nome[0]='\0';
			strcat(nome, argv[2]);
		}
		
		if(strstr(nome, ".tac") == NULL)
			strcat(nome, ".tac");
			
		saida = fopen(nome, "w");
		
		if(saida == NULL)
			usage(argv[0]);
			
		outfile = 1;

		if(strcmp(argv[1], "-o") != 0)
		{
			nome=malloc(sizeof(char)*(strlen(argv[1])+ 1));
			strcpy(nome, argv[1]);
		}
		else
		{
			nome=malloc(sizeof(char)*(strlen(argv[3])+1));
			strcpy(nome, argv[3]);
		}
	}
	else 
	{
		nome=malloc(sizeof(char)*(strlen(argv[1])+1));
		strcpy(nome, argv[1]);
	}

	yyin = fopen(nome, "r");

	if (!yyin) {
		printf("Uso: %s <input_file>. Could not find %s. Try again!\n",			argv[0], nome);
		exit(-1);
	}
	progname=argv[0];

	if (!yyparse()) {

		codigo_tac=((node_tac *)syntax_tree->attribute);
		if(outfile)
			fprintf(saida, "%d\n%d\n", desloc, temp);
		else
			fprintf(stderr, "%d\n%d\n", desloc, temp);
				
		if(outfile)
			print_tac(saida, codigo_tac);
		else
			print_tac(stderr, codigo_tac);
	} else 
		fprintf(stderr, "ERROR.\n");
	print_table(symbol_table);
	return(0);
}
yyerror(char* s) {
	fprintf(stderr, "%s: %s", progname, s);
}
